/*
* Copyright (c) 2020 The canvas Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
  found in the LICENSE file.

* Author:         dzlua - https://gitee.com/dzlua/canvas.git
* Email:          505544956@qq.com
* FileName:       canvas_impl.h
* Create Time:    2020/01/01 15:12:47
* Description:    /
*/

#ifndef __CANVAS_IMPL_H__
#define __CANVAS_IMPL_H__

#include <canvas.h>
#include "dynamic_library.h"

#include <vector>
#include <string>

/////////////////////////////////////
// for exports
// windows
#if defined(I_OS_WIN)
  #ifdef CVS_RENDER_EXPORT
    #define CVS_RENDER_API __declspec(dllexport)
  #else
    #define CVS_RENDER_API __declspec(dllimport)
  #endif

// linux
#elif defined(I_OS_LINUX)
  #ifdef CVS_RENDER_EXPORT
    #define CVS_RENDER_API __attribute__((visibility("default")))
  #else
    #define CVS_RENDER_API 
  #endif

// others
#else
  #define CVS_RENDER_API 

#endif

namespace cvs {
  class Factory;

  enum class C2DorC3D : uint8 {
    C2D, C3D
  };

  namespace c2d {
    #ifdef __cplusplus
      extern "C" {
    #endif // __cplusplus
    
    CVS_RENDER_API RenderType render_type();
    CVS_RENDER_API Result create_render(IFactory *factory, IRender **render);
    
    #ifdef __cplusplus
      }
    #endif // cplusplus
  } // end namespace c2d

  namespace c3d {
    #ifdef __cplusplus
      extern "C" {
    #endif // __cplusplus
    
    CVS_RENDER_API RenderType render_type();
    CVS_RENDER_API Result create_render(IFactory *factory, IRender **render);
    
    #ifdef __cplusplus
      }
    #endif // cplusplus
  } // end namespace c3d

  #ifdef __cplusplus
    extern "C" {
  #endif // __cplusplus

  // render is 2d or 3d.
  CVS_RENDER_API C2DorC3D c2d_or_c3d();
  // render is supported in current system.
  CVS_RENDER_API bool supported();

  #ifdef __cplusplus
    }
  #endif // cplusplus
} // end namespace cvs

namespace cvs {
  class CVS_API Base : virtual public IBase {
    public:
      virtual ulong decref() override;
      virtual ulong incref() override;
    protected:
      Base();
      virtual ~Base();
    protected:
      ulong ref_count_;
  };

  class CVS_API Factory : public Base, virtual public IFactory {
    public:
      virtual Result load_render(const char *name) override;
      virtual Result unload_render(const char *name) override;
      virtual Result unload_all_render() override;
      virtual bool is_render_loaded(const char *name) const override;
      virtual Result create_2d_render(c2d::IRender **render, c2d::RenderType type = c2d::RenderType::Default) override;
      virtual Result create_3d_render(c3d::IRender **render, c3d::RenderType type = c3d::RenderType::Default) override;
    protected:
      Result create_default_2d_render(c2d::IRender **render);
      Result create_default_3d_render(c3d::IRender **render);
    protected:
      friend Result create_factory(IFactory **factory);
      Factory();
      virtual ~Factory();
    protected:
      struct dlRender {
        std::string name;
        IDynamicLibrary *dl;
        C2DorC3D c2d3d;
        c2d::RenderType c2d;
        c3d::RenderType c3d;
        Result (*create2dRender)(IFactory *factory, c2d::IRender **render);
        Result (*create3dRender)(IFactory *factory, c3d::IRender **render);
      };
      std::vector<dlRender> renders_;
  };

} // end namespace cvs

#endif // __CANVAS_IMPL_H__